package me.itsoo.artemis.framework.core.thread;

import me.itsoo.artemis.framework.core.util.Assert;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;

/**
 * ThreadFactoryBuilder
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/6/2
 */
public final class ThreadFactoryBuilder {

    private String nameFormat;

    private Boolean daemon;

    private Integer priority;

    private ThreadFactory backingThreadFactory;

    public ThreadFactoryBuilder() {}

    public ThreadFactoryBuilder setNameFormat(String nameFormat) {
        String unused = String.format(nameFormat, 0);
        this.nameFormat = nameFormat;
        return this;
    }

    public ThreadFactoryBuilder setDaemon(boolean daemon) {
        this.daemon = daemon;
        return this;
    }

    public ThreadFactoryBuilder setPriority(int priority) {
        Assert.isTrue(priority >= Thread.MIN_PRIORITY, "'priority' must be >= " + Thread.MIN_PRIORITY);
        Assert.isTrue(priority <= Thread.MAX_PRIORITY, "'priority' must be <= " + Thread.MAX_PRIORITY);
        this.priority = priority;
        return this;
    }

    public ThreadFactoryBuilder setThreadFactory(ThreadFactory backingThreadFactory) {
        Assert.notNull(backingThreadFactory, "'backingThreadFactory' cannot be null");
        this.backingThreadFactory = backingThreadFactory;
        return this;
    }

    public ThreadFactory build() {
        return build(this);
    }

    private static ThreadFactory build(ThreadFactoryBuilder builder) {

        final String nameFormat = builder.nameFormat;

        final Boolean daemon = builder.daemon;

        final Integer priority = builder.priority;

        final ThreadFactory backingThreadFactory = (builder.backingThreadFactory != null)
                ? builder.backingThreadFactory
                : Executors.defaultThreadFactory();

        final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;

        return t -> {
            final Thread thread = backingThreadFactory.newThread(t);
            if (nameFormat != null) {
                thread.setName(String.format(nameFormat, count.getAndIncrement()));
            }
            if (daemon != null) {
                thread.setDaemon(daemon);
            }
            if (priority != null) {
                thread.setPriority(priority);
            }
            return thread;
        };
    }
}
